#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>

#define NUM 1024
#define SIZE 32
#define SEP " " //char *strtok(char *str, const char *delim);

//保存完整的命令行字符串
char cmd_line[NUM]={0};
//保存打散后的命令行字符串
char *g_argv[SIZE];


//写一个环境变量buffer[],用来测试
char g_myval[64];

//shell 运行原理:通过让子进程执行命令，父进程等待&&解析命令

int main()
{
    //命令行解释器，一定是一个常驻内存的进程，不退出
  while(1)
  {
      //1.打印出提示信息"[root@VM-4-14-centos ~]#"
      printf("[root@VM-4-14-centos ~]#");
      fflush(stdout);
      memset(cmd_line,'\0',sizeof cmd_line);

      //2.获取用户在键盘上的输入(输入的是各种指令和选项"ls  -l  -a")
       if(fgets(cmd_line,sizeof cmd_line,stdin)==NULL)
       {
           continue;
       }
     // printf("%d\n",strlen(cmd_line));//ls -a'\n'
      cmd_line[strlen(cmd_line)-1]='\0';//将'\n'变为'\0'
    // printf("echo:%s\n",cmd_line);
    
    //3.命令行字符串的解析:"ls -l -a -i"->"ls" "-l" "-a" "-i"
     g_argv[0]=strtok(cmd_line,SEP);//第一次调用，要传入原始字符串
   

     int index=1;
     if(strcmp(g_argv[0],"ls")==0)
     {
         g_argv[index++]="--color=auto";
     }

     if(strcmp(g_argv[0],"ll")==0)
     {
         g_argv[0]="ls";
         g_argv[index++]="-l";
         g_argv[index++]="--color=auto";
     }

     while(g_argv[index++]=strtok(NULL,SEP));//第二次,如果还要解析字符串，要传入NULL
     if(strcmp(g_argv[0],"export")==0&&g_argv[1]!=NULL)
     {
        strcpy(g_myval,g_argv[1]);
        int ret=putenv(g_myval);
        if(ret==0)printf("%s export success\n",g_argv[1]);
        continue;
     }


     //debug
     //for(index=0;g_argv[index];index++)
     //{
     //    printf("g_argv[%d]:%s\n",index,g_argv[index]);
     //}

    //4.TODO内置命令，让父进程自己执行的命令，我们叫内置命令，内建命令
    //内建命令本质是shell中的一个函数调用
    if(strcmp(g_argv[0],"cd")==0)
    {
      if(g_argv[1]!=NULL)
      chdir(g_argv[1]); //  int chdir(const char *path);

      continue;
    }

    //fork()
    pid_t id=fork();
    if(id==0)
    {
        printf("下面功能子进程进行\n");
        printf("child, MYVAL: %s\n",getenv("MYVAL"));
        printf("child, PATH: %s\n",getenv("PATH"));

        execvp(g_argv[0],g_argv);
        exit(1);
    }
    else
    {
        int status=0;
        pid_t ret =waitpid(id,&status,0);
        if(ret>0)
            printf("exit code:%d\n",WEXITSTATUS(status));
    }
     
  }
}
